package com.wu.service.impl;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wu.error.BusinessException;
import com.wu.error.EnumBusinessError;
import com.wu.mapper.ArticlesMapper;
import com.wu.mapper.CommentReportMapper;
import com.wu.mapper.CommentsMapper;
import com.wu.mapper.UsersMapper;
import com.wu.pojo.Comments;
import com.wu.pojo.model.CommentModel;
import com.wu.pojo.model.NewCommentsModel;
import com.wu.pojo.model.UserToken;
import com.wu.service.ArticlesService;
import com.wu.service.CommentsService;
import com.wu.util.MyUtil;
import com.wu.util.TokenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.wu.constant.Constant.*;

/**
 * @author: 吴磊
 * @program: blog
 * @create: 2021-04-19 20:31
 */
@Service
public class CommentsServiceImpl extends ServiceImpl<CommentsMapper,Comments> implements CommentsService {

    @Autowired
    private CommentsMapper commentsMapper;

    @Autowired
    private TokenUtils tokenUtils;

    @Autowired
    private MyUtil myUtil;

    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private ArticlesMapper articlesMapper;

    @Autowired
    private ArticlesService articlesService;

    @Autowired
    private CommentReportMapper commentReportMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            readOnly = false,
            timeout = 100,
            noRollbackForClassName = {"RunTimeException"}
    )
    @Override
    public Map<String, Object> addComment(String type, String articleId, String parentCommentId, String commentContent) {
        Map<String, Object> map = new HashMap<>();
        String commentId = IdWorker.get32UUID();
        String commentDate = myUtil.getCurrentDetailedTime();
        UserToken userToken = tokenUtils.parseTokenToUserToken();
        String userId = userToken.getUserId();
        Comments comments = new Comments();
        comments.setCommentId(commentId);
        comments.setUserId(userId);
        comments.setArticleId(articleId);
        comments.setCommentDate(commentDate);
        comments.setCommentContent(commentContent);
        if (BLOG.equals(type)) {
            //说明这个是一个一级评论
            comments.setParentCommentId(DEFAULT_NULL_VALUE);
        } else {
            //说明这是一个回复
            comments.setParentCommentId(parentCommentId);
        }
        //添加评论或者回复之前，先判断是否是自己的文章
        String articleUserId = articlesMapper.getUserIdByArticleId(articleId);
        if (userId.equals(articleUserId)) {
            //说明是自己的文章，可以直接通过审核
            comments.setCommentStatus(ONE);
            redisTemplate.opsForValue().increment(articleId + _COMMENT_COUNT);
            redisTemplate.opsForValue().increment(userId + _COMMENT_COUNT);
        } else {
            String userIdByArticleId = articlesMapper.getUserIdByArticleId(articleId);
            if (redisTemplate.opsForSet().isMember(IS_ENABLE_COMMENT_AUDIT, userIdByArticleId)) {
                comments.setCommentStatus(ZERO);
            } else {
                comments.setCommentStatus(ONE);
            }
        }
        Integer integer = commentsMapper.addComment(comments);
        if (integer <= 0) {
            throw new BusinessException(EnumBusinessError.UNKNOWN_ERROR, "评论失败");
        }
        map.put(COUNT, redisTemplate.opsForValue().get(articleId + _COMMENT_COUNT));
        return map;
    }

    //TODO:文章评论分页
    @Override
    public List<CommentModel> getAllCommentByArticleId(String articleId) {
        List<CommentModel> levelOneComment = commentsMapper.getCommentsByArticleIdAndParentCommentIdIsNull(articleId);
        levelOneComment = getCommentModels(levelOneComment);
        return getSons(levelOneComment);
    }

    private List<CommentModel> getCommentModels(List<CommentModel> levelOneComment) {
        levelOneComment = levelOneComment.stream().peek(comment -> {
            long longTime = System.currentTimeMillis();
            String commentDate = comment.getCommentDate();
            long commentTime = myUtil.parseTimeToString(commentDate);
            long time = longTime - commentTime;
            String overdueTime = "";
            long howTime = time / 1000 / 60;
            if (howTime < 60) {
                overdueTime = howTime + "分钟前";
            } else if (howTime < 1440) {
                overdueTime = howTime / 60 + "小时前";
            } else if (howTime < 43200) {
                overdueTime = howTime / 1440 + "天前";
            } else if (howTime < 15768000) {
                overdueTime = howTime / 43200 + "月前";
            } else {
                overdueTime = howTime / 15768000 + "年前";
            }
            comment.setOverdueTime(overdueTime);
        }).collect(Collectors.toList());
        return levelOneComment;
    }

    @Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            readOnly = false,
            timeout = 100,
            noRollbackForClassName = {"RunTimeException"}
    )
    @Override
    public Map<String, Object> deleteCommentsByCommentId(String commentId) {
        Comments comments = commentsMapper.getCommentsByCommentId(commentId);
        //获取当前评论对应的文章ID
        String articleId = articlesMapper.getArticleIdByCommentsId(commentId);
        if (comments == null) {
            Integer count = (Integer) redisTemplate.opsForValue().get(articleId + _COMMENT_COUNT);
            Map<String, Object> map = new HashMap<>();
            map.put(COUNT, count);
            return map;
        }
        List<String> list = new ArrayList();
        list.add(commentId);
        List<CommentModel> sons = getSons(commentId);
        getChildComments(sons, list);
        //以上获取了所有评论的Id，下面就可以根据这些评论Id删除评论举报了
        commentReportMapper.deleteCommentReportsByCommentIds(list);
        list.forEach(id -> redisTemplate.delete(id));
        redisTemplate.opsForValue().decrement(articleId + _COMMENT_COUNT, list.size());
        String userId = articlesMapper.getUserIdByArticleId(articleId);
        redisTemplate.opsForValue().decrement(userId + _COMMENT_COUNT, list.size());
        commentsMapper.deleteCommentsById(list);
        Map<String, Object> map = new HashMap<>();
        map.put("count", redisTemplate.opsForValue().get(articleId + _COMMENT_COUNT));
        return map;
    }

    @Override
    public void passCommentByCommentId(String commentId) {
        // 这里有个小逻辑：没有父评论，或者说父评论还在审核中，哪来的子评论？所以：直接通过即可
        Integer integer = commentsMapper.passCommentByCommentId(commentId);
        if (integer <= 0) {
            throw new BusinessException(EnumBusinessError.UNKNOWN_ERROR, "通过审核失败，请稍后再试");
        }
        String userId = commentsMapper.getUserIdByCommentId(commentId);
        redisTemplate.opsForValue().increment(userId + _COMMENT_COUNT);
        String articleId = commentsMapper.getArticleIdByCommentId(commentId);
        articlesService.addArticleComments(articleId);
    }

    @Override
    public void notPassCommentByCommentId(String commentId) {
        Integer integer = commentsMapper.deleteOneById(commentId);
        if (integer <= 0) {
            throw new BusinessException(EnumBusinessError.UNKNOWN_ERROR, "评论不通过的时候删除评论失败");
        }
    }

    @Override
    public Map<String, Object> getNewComments(String userId) {
        Map<String, Object> map = new HashMap<>();
        List<NewCommentsModel> newComments = commentsMapper.getNewComments(userId);
        map.put(COMMENTS, newComments);
        return map;
    }


    private void getChildComments(List<CommentModel> children, List<String> list) {
        if (children == null || children.isEmpty()) {
            return;
        }
        for (CommentModel child : children) {
            String commentId = child.getCommentId();
            list.add(commentId);
            List<CommentModel> sons = getSons(commentId);
            getChildComments(sons, list);
        }
    }

    /**
     * 通过父评论Id获取子评论
     *
     * @param parentCommentsId
     * @return
     */
    private List<CommentModel> getSons(String parentCommentsId) {
        return commentsMapper.getCommentByParentId(parentCommentsId);
    }

    /**
     * 递归查询子评论
     *
     * @param parents
     * @return
     */
    private List<CommentModel> getSons(List<CommentModel> parents) {
        if (parents == null || parents.isEmpty()) {
            return Collections.emptyList();
        }
        for (CommentModel parent : parents) {
            UserToken userInfo = usersMapper.getUserTokenById(parent.getUserId());
            parent.setUserToken(userInfo);
            String parentCommentId = parent.getCommentId();
            List<CommentModel> sons = getSons(parentCommentId);
            sons = getCommentModels(sons);
            parent.setChildComment(getSons(sons));
        }
        return parents;
    }
}
